home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / apps / math / ols.zoo / split.c < prev    next >
C/C++ Source or Header  |  1993-04-16  |  9KB  |  586 lines

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include "utils.h"
  4.  
  5. #ifdef TESTING
  6. #define MAXF 3
  7. int 
  8. main ()
  9. {
  10.   int i, numfields;
  11.   char thisline[1000];
  12.   char **words;
  13.  
  14.   printf ("For today, atmost %d fields/line.  FS = | only.\n", MAXF);
  15.   words = (char **) malloc (MAXF * sizeof (char *));
  16.   do
  17.     {
  18.       printf ("\n\nEnter a line: ");
  19.       if (NULL == gets (thisline))
  20.     break;
  21.       else
  22.     {
  23.       numfields = split (thisline, words, MAXF, "|");
  24.       printf ("\n%d fields.\n", numfields);
  25.       for (i = 0; i < (numfields > MAXF ? MAXF : numfields); i++)
  26.         printf ("%s\n", words[i]);
  27.     }
  28.     }
  29.   while (1 == 1);
  30.  
  31.   return 0;
  32. }
  33.  
  34. #endif /* TESTING */
  35.  
  36. /*
  37.  * split - divide a string into fields, like awk split()
  38.  */
  39. int                /* number of fields, including overflow */
  40. split (string, fields, nfields, sep)
  41.      char *string;
  42.      char *fields[];        /* list is not NULL-terminated */
  43.      int nfields;        /* number of entries available in fields[] */
  44.      char *sep;            /* "" white, "c" single char, "ab" [ab]+ */
  45. {
  46.   register char *p = string;
  47.   register char c;        /* latest character */
  48.   register char sepc = sep[0];
  49.   register char sepc2;
  50.   register int fn;
  51.   register char **fp = fields;
  52.   register char *sepp;
  53.   register int trimtrail;
  54.  
  55.   /* white space */
  56.   if (sepc == '\0')
  57.     {
  58.       while ((c = *p++) == ' ' || c == '\t')
  59.     continue;
  60.       p--;
  61.       trimtrail = 1;
  62.       sep = " \t";        /* note, code below knows this is 2 long */
  63.       sepc = ' ';
  64.     }
  65.   else
  66.     trimtrail = 0;
  67.   sepc2 = sep[1];        /* now we can safely pick this up */
  68.  
  69.   /* catch empties */
  70.   if (*p == '\0')
  71.     return (0);
  72.  
  73.   /* single separator */
  74.   if (sepc2 == '\0')
  75.     {
  76.       fn = nfields;
  77.       for (;;)
  78.     {
  79.       *fp++ = p;
  80.       fn--;
  81.       if (fn == 0)
  82.         break;
  83.       while ((c = *p++) != sepc)
  84.         if (c == '\0')
  85.           return (nfields - fn);
  86.       *(p - 1) = '\0';
  87.     }
  88.       /* we have overflowed the fields vector -- just count them */
  89.       fn = nfields;
  90.       for (;;)
  91.     {
  92.       while ((c = *p++) != sepc)
  93.         if (c == '\0')
  94.           return (fn);
  95.       fn++;
  96.     }
  97.       /* not reached */
  98.     }
  99.  
  100.   /* two separators */
  101.   if (sep[2] == '\0')
  102.     {
  103.       fn = nfields;
  104.       for (;;)
  105.     {
  106.       *fp++ = p;
  107.       fn--;
  108.       while ((c = *p++) != sepc && c != sepc2)
  109.         if (c == '\0')
  110.           {
  111.         if (trimtrail && **(fp - 1) == '\0')
  112.           fn++;
  113.         return (nfields - fn);
  114.           }
  115.       if (fn == 0)
  116.         break;
  117.       *(p - 1) = '\0';
  118.       while ((c = *p++) == sepc || c == sepc2)
  119.         continue;
  120.       p--;
  121.     }
  122.       /* we have overflowed the fields vector -- just count them */
  123.       fn = nfields;
  124.       while (c != '\0')
  125.     {
  126.       while ((c = *p++) == sepc || c == sepc2)
  127.         continue;
  128.       p--;
  129.       fn++;
  130.       while ((c = *p++) != '\0' && c != sepc && c != sepc2)
  131.         continue;
  132.     }
  133.       /* might have to trim trailing white space */
  134.       if (trimtrail)
  135.     {
  136.       p--;
  137.       while ((c = *--p) == sepc || c == sepc2)
  138.         continue;
  139.       p++;
  140.       if (*p != '\0')
  141.         {
  142.           if (fn == nfields + 1)
  143.         *p = '\0';
  144.           fn--;
  145.         }
  146.     }
  147.       return (fn);
  148.     }
  149.  
  150.   /* n separators */
  151.   fn = 0;
  152.   for (;;)
  153.     {
  154.       if (fn < nfields)
  155.     *fp++ = p;
  156.       fn++;
  157.       for (;;)
  158.     {
  159.       c = *p++;
  160.       if (c == '\0')
  161.         return (fn);
  162.       sepp = sep;
  163.       while ((sepc = *sepp++) != '\0' && sepc != c)
  164.         continue;
  165.       if (sepc != '\0')    /* it was a separator */
  166.         break;
  167.     }
  168.       if (fn < nfields)
  169.     *(p - 1) = '\0';
  170.       for (;;)
  171.     {
  172.       c = *p++;
  173.       sepp = sep;
  174.       while ((sepc = *sepp++) != '\0' && sepc != c)
  175.         continue;
  176.       if (sepc == '\0')    /* it wasn't a separator */
  177.         break;
  178.     }
  179.       p--;
  180.     }
  181.  
  182.   /* not reached */
  183. }
  184.  
  185. #ifdef TEST_SPLIT
  186.  
  187.  
  188. /*
  189.  * test program
  190.  * pgm        runs regression
  191.  * pgm sep    splits stdin lines by sep
  192.  * pgm str sep    splits str by sep
  193.  * pgm str sep n    splits str by sep n times
  194.  */
  195. int
  196. main (argc, argv)
  197.      int argc;
  198.      char *argv[];
  199. {
  200.   char buf[512];
  201.   register int n;
  202. #    define    MNF    10
  203.   char *fields[MNF];
  204.  
  205.   if (argc > 4)
  206.     for (n = atoi (argv[3]); n > 0; n--)
  207.       {
  208.     (void) strcpy (buf, argv[1]);
  209.       }
  210.   else if (argc > 3)
  211.     for (n = atoi (argv[3]); n > 0; n--)
  212.       {
  213.     (void) strcpy (buf, argv[1]);
  214.     (void) split (buf, fields, MNF, argv[2]);
  215.       }
  216.   else if (argc > 2)
  217.     dosplit (argv[1], argv[2]);
  218.   else if (argc > 1)
  219.     while (fgets (buf, sizeof (buf), stdin) != NULL)
  220.       {
  221.     buf[strlen (buf) - 1] = '\0';    /* stomp newline */
  222.     dosplit (buf, argv[1]);
  223.       }
  224.   else
  225.     regress ();
  226.  
  227.   exit (0);
  228. }
  229.  
  230. dosplit (string, seps)
  231.      char *string;
  232.      char *seps;
  233. {
  234. #    define    NF    5
  235.   char *fields[NF];
  236.   register int nf;
  237.  
  238.   nf = split (string, fields, NF, seps);
  239.   print (nf, fields);
  240. }
  241.  
  242. print (nf, fields)
  243.      int nf;
  244.      char *fields[];
  245. {
  246.   register int fn;
  247.  
  248.   printf ("%d:\t", nf);
  249.   for (fn = 0; fn < nf; fn++)
  250.     printf ("\"%s\"%s", fields[fn], (fn + 1 < nf) ? ", " : "\n");
  251. }
  252.  
  253. #define    RNF    5        /* some table entries know this */
  254. struct
  255.   {
  256.     char *str;
  257.     char *seps;
  258.     int nf;
  259.     char *fi[RNF];
  260.   }
  261.  
  262. tests[] =
  263. {
  264.   "", " ", 0,
  265.   {
  266.     ""
  267.   }
  268.   ,
  269.   " ", " ", 2,
  270.   {
  271.     "", ""
  272.   }
  273.   ,
  274.   "x", " ", 1,
  275.   {
  276.     "x"
  277.   }
  278.   ,
  279.   "xy", " ", 1,
  280.   {
  281.     "xy"
  282.   }
  283.   ,
  284.   "x y", " ", 2,
  285.   {
  286.     "x", "y"
  287.   }
  288.   ,
  289.   "abc def  g ", " ", 5,
  290.   {
  291.     "abc", "def", "", "g", ""
  292.   }
  293.   ,
  294.   "  a bcd", " ", 4,
  295.   {
  296.     "", "", "a", "bcd"
  297.   }
  298.   ,
  299.   "a b c d e f", " ", 6,
  300.   {
  301.     "a", "b", "c", "d", "e f"
  302.   }
  303.   ,
  304.   " a b c d ", " ", 6,
  305.   {
  306.     "", "a", "b", "c", "d "
  307.   }
  308.   ,
  309.  
  310.   "", " _", 0,
  311.   {
  312.     ""
  313.   }
  314.   ,
  315.   " ", " _", 2,
  316.   {
  317.     "", ""
  318.   }
  319.   ,
  320.   "x", " _", 1,
  321.   {
  322.     "x"
  323.   }
  324.   ,
  325.   "x y", " _", 2,
  326.   {
  327.     "x", "y"
  328.   }
  329.   ,
  330.   "ab _ cd", " _", 2,
  331.   {
  332.     "ab", "cd"
  333.   }
  334.   ,
  335.   " a_b     c ", " _", 5,
  336.   {
  337.     "", "a", "b", "c", ""
  338.   }
  339.   ,
  340.   "a b c_d e f", " _", 6,
  341.   {
  342.     "a", "b", "c", "d", "e f"
  343.   }
  344.   ,
  345.   " a b c d ", " _", 6,
  346.   {
  347.     "", "a", "b", "c", "d "
  348.   }
  349.   ,
  350.  
  351.   "", " _~", 0,
  352.   {
  353.     ""
  354.   }
  355.   ,
  356.   " ", " _~", 2,
  357.   {
  358.     "", ""
  359.   }
  360.   ,
  361.   "x", " _~", 1,
  362.   {
  363.     "x"
  364.   }
  365.   ,
  366.   "x y", " _~", 2,
  367.   {
  368.     "x", "y"
  369.   }
  370.   ,
  371.   "ab _~ cd", " _~", 2,
  372.   {
  373.     "ab", "cd"
  374.   }
  375.   ,
  376.   " a_b     c~", " _~", 5,
  377.   {
  378.     "", "a", "b", "c", ""
  379.   }
  380.   ,
  381.   "a b_c d~e f", " _~", 6,
  382.   {
  383.     "a", "b", "c", "d", "e f"
  384.   }
  385.   ,
  386.   "~a b c d ", " _~", 6,
  387.   {
  388.     "", "a", "b", "c", "d "
  389.   }
  390.   ,
  391.  
  392.   "", " _~-", 0,
  393.   {
  394.     ""
  395.   }
  396.   ,
  397.   " ", " _~-", 2,
  398.   {
  399.     "", ""
  400.   }
  401.   ,
  402.   "x", " _~-", 1,
  403.   {
  404.     "x"
  405.   }
  406.   ,
  407.   "x y", " _~-", 2,
  408.   {
  409.     "x", "y"
  410.   }
  411.   ,
  412.   "ab _~- cd", " _~-", 2,
  413.   {
  414.     "ab", "cd"
  415.   }
  416.   ,
  417.   " a_b     c~", " _~-", 5,
  418.   {
  419.     "", "a", "b", "c", ""
  420.   }
  421.   ,
  422.   "a b_c-d~e f", " _~-", 6,
  423.   {
  424.     "a", "b", "c", "d", "e f"
  425.   }
  426.   ,
  427.   "~a-b c d ", " _~-", 6,
  428.   {
  429.     "", "a", "b", "c", "d "
  430.   }
  431.   ,
  432.  
  433.   "", "     ", 0,
  434.   {
  435.     ""
  436.   }
  437.   ,
  438.   " ", "  ", 2,
  439.   {
  440.     "", ""
  441.   }
  442.   ,
  443.   "x", "  ", 1,
  444.   {
  445.     "x"
  446.   }
  447.   ,
  448.   "xy", "  ", 1,
  449.   {
  450.     "xy"
  451.   }
  452.   ,
  453.   "x y", "  ", 2,
  454.   {
  455.     "x", "y"
  456.   }
  457.   ,
  458.   "abc def  g ", "  ", 4,
  459.   {
  460.     "abc", "def", "g", ""
  461.   }
  462.   ,
  463.   "  a bcd", "    ", 3,
  464.   {
  465.     "", "a", "bcd"
  466.   }
  467.   ,
  468.   "a b c d e f", "  ", 6,
  469.   {
  470.     "a", "b", "c", "d", "e f"
  471.   }
  472.   ,
  473.   " a b c d ", "  ", 6,
  474.   {
  475.     "", "a", "b", "c", "d "
  476.   }
  477.   ,
  478.  
  479.   "", "", 0,
  480.   {
  481.     ""
  482.   }
  483.   ,
  484.   " ", "", 0,
  485.   {
  486.     ""
  487.   }
  488.   ,
  489.   "x", "", 1,
  490.   {
  491.     "x"
  492.   }
  493.   ,
  494.   "xy", "", 1,
  495.   {
  496.     "xy"
  497.   }
  498.   ,
  499.   "x y", "", 2,
  500.   {
  501.     "x", "y"
  502.   }
  503.   ,
  504.   "abc def  g ", "", 3,
  505.   {
  506.     "abc", "def", "g"
  507.   }
  508.   ,
  509.   "\t a bcd", "", 2,
  510.   {
  511.     "a", "bcd"
  512.   }
  513.   ,
  514.   "  a \tb\t c ", "", 3,
  515.   {
  516.     "a", "b", "c"
  517.   }
  518.   ,
  519.   "a b\tc d e f", "", 6,
  520.   {
  521.     "a", "b", "c", "d", "e f"
  522.   }
  523.   ,
  524.   " a b c d e f ", "", 6,
  525.   {
  526.     "a", "b", "c", "d", "e f "
  527.   }
  528.   ,
  529.  
  530.   NULL, NULL, 0,
  531.   {
  532.     NULL
  533.   }
  534.   ,
  535. };
  536.  
  537. regress ()
  538. {
  539.   char buf[512];
  540.   register int n;
  541.   char *fields[RNF + 1];
  542.   register int nf;
  543.   register int i;
  544.   register int printit;
  545.   register char *f;
  546.  
  547.   for (n =